home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / mysqli.php < prev    next >
PHP Script  |  2004-10-01  |  31KB  |  961 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Daniel Convissor <danielc@php.net>                           |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: mysqli.php,v 1.31 2004/07/12 17:51:24 danielc Exp $
  20.  
  21.  
  22. // EXPERIMENTAL
  23.  
  24.  
  25. require_once 'DB/common.php';
  26.  
  27. /**
  28.  * Database independent query interface definition for PHP's mysqli
  29.  * extension.
  30.  *
  31.  * This is for MySQL versions 4.1 and above.  Requires PHP 5.
  32.  *
  33.  * Note that persistent connections no longer exist.
  34.  *
  35.  * @package  DB
  36.  * @version  $Id: mysqli.php,v 1.31 2004/07/12 17:51:24 danielc Exp $
  37.  * @category Database
  38.  * @author   Daniel Convissor <danielc@php.net>
  39.  * @since    Class functional since Release 1.6.3
  40.  */
  41. class DB_mysqli extends DB_common
  42. {
  43.     // {{{ properties
  44.  
  45.     var $connection;
  46.     var $phptype, $dbsyntax;
  47.     var $prepare_tokens = array();
  48.     var $prepare_types = array();
  49.     var $num_rows = array();
  50.     var $transaction_opcount = 0;
  51.     var $autocommit = true;
  52.     var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */
  53.     var $_db = false;
  54.  
  55.     /**
  56.      * Array for converting MYSQLI_*_FLAG constants to text values
  57.      * @var    array
  58.      * @access public
  59.      * @since  Property available since Release 1.6.5
  60.      */
  61.     var $mysqli_flags = array(
  62.         MYSQLI_NOT_NULL_FLAG        => 'not_null',
  63.         MYSQLI_PRI_KEY_FLAG         => 'primary_key',
  64.         MYSQLI_UNIQUE_KEY_FLAG      => 'unique_key',
  65.         MYSQLI_MULTIPLE_KEY_FLAG    => 'multiple_key',
  66.         MYSQLI_BLOB_FLAG            => 'blob',
  67.         MYSQLI_UNSIGNED_FLAG        => 'unsigned',
  68.         MYSQLI_ZEROFILL_FLAG        => 'zerofill',
  69.         MYSQLI_AUTO_INCREMENT_FLAG  => 'auto_increment',
  70.         MYSQLI_TIMESTAMP_FLAG       => 'timestamp',
  71.         MYSQLI_SET_FLAG             => 'set',
  72.         // MYSQLI_NUM_FLAG             => 'numeric',  // unnecessary
  73.         // MYSQLI_PART_KEY_FLAG        => 'multiple_key',  // duplicatvie
  74.         MYSQLI_GROUP_FLAG           => 'group_by'
  75.     );
  76.  
  77.     /**
  78.      * Array for converting MYSQLI_TYPE_* constants to text values
  79.      * @var    array
  80.      * @access public
  81.      * @since  Property available since Release 1.6.5
  82.      */
  83.     var $mysqli_types = array(
  84.         MYSQLI_TYPE_DECIMAL     => 'decimal',
  85.         MYSQLI_TYPE_TINY        => 'tinyint',
  86.         MYSQLI_TYPE_SHORT       => 'int',
  87.         MYSQLI_TYPE_LONG        => 'int',
  88.         MYSQLI_TYPE_FLOAT       => 'float',
  89.         MYSQLI_TYPE_DOUBLE      => 'double',
  90.         // MYSQLI_TYPE_NULL        => 'DEFAULT NULL',  // let flags handle it
  91.         MYSQLI_TYPE_TIMESTAMP   => 'timestamp',
  92.         MYSQLI_TYPE_LONGLONG    => 'bigint',
  93.         MYSQLI_TYPE_INT24       => 'mediumint',
  94.         MYSQLI_TYPE_DATE        => 'date',
  95.         MYSQLI_TYPE_TIME        => 'time',
  96.         MYSQLI_TYPE_DATETIME    => 'datetime',
  97.         MYSQLI_TYPE_YEAR        => 'year',
  98.         MYSQLI_TYPE_NEWDATE     => 'date',
  99.         MYSQLI_TYPE_ENUM        => 'enum',
  100.         MYSQLI_TYPE_SET         => 'set',
  101.         MYSQLI_TYPE_TINY_BLOB   => 'tinyblob',
  102.         MYSQLI_TYPE_MEDIUM_BLOB => 'mediumblob',
  103.         MYSQLI_TYPE_LONG_BLOB   => 'longblob',
  104.         MYSQLI_TYPE_BLOB        => 'blob',
  105.         MYSQLI_TYPE_VAR_STRING  => 'varchar',
  106.         MYSQLI_TYPE_STRING      => 'char',
  107.         MYSQLI_TYPE_GEOMETRY    => 'geometry',
  108.     );
  109.  
  110.     // }}}
  111.     // {{{ constructor
  112.  
  113.     /**
  114.      * DB_mysql constructor.
  115.      *
  116.      * @access public
  117.      */
  118.     function DB_mysqli()
  119.     {
  120.         $this->DB_common();
  121.         $this->phptype = 'mysqli';
  122.         $this->dbsyntax = 'mysqli';
  123.         $this->features = array(
  124.             'prepare' => false,
  125.             'ssl' => true,
  126.             'transactions' => true,
  127.             'limit' => 'alter'
  128.         );
  129.         $this->errorcode_map = array(
  130.             1004 => DB_ERROR_CANNOT_CREATE,
  131.             1005 => DB_ERROR_CANNOT_CREATE,
  132.             1006 => DB_ERROR_CANNOT_CREATE,
  133.             1007 => DB_ERROR_ALREADY_EXISTS,
  134.             1008 => DB_ERROR_CANNOT_DROP,
  135.             1022 => DB_ERROR_ALREADY_EXISTS,
  136.             1046 => DB_ERROR_NODBSELECTED,
  137.             1048 => DB_ERROR_CONSTRAINT,
  138.             1050 => DB_ERROR_ALREADY_EXISTS,
  139.             1051 => DB_ERROR_NOSUCHTABLE,
  140.             1054 => DB_ERROR_NOSUCHFIELD,
  141.             1062 => DB_ERROR_ALREADY_EXISTS,
  142.             1064 => DB_ERROR_SYNTAX,
  143.             1100 => DB_ERROR_NOT_LOCKED,
  144.             1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
  145.             1146 => DB_ERROR_NOSUCHTABLE,
  146.             1216 => DB_ERROR_CONSTRAINT,
  147.             1217 => DB_ERROR_CONSTRAINT,
  148.         );
  149.     }
  150.  
  151.     // }}}
  152.     // {{{ connect()
  153.  
  154.     /**
  155.      * Connect to a database and log in as the specified user.
  156.      *
  157.      * @param string $dsn the data source name (see DB::parseDSN for syntax)
  158.      * @param boolean $persistent (optional) whether the connection should
  159.      *                            be persistent
  160.      * @return mixed DB_OK on success, a DB error on failure
  161.      * @access public
  162.      */
  163.     function connect($dsninfo, $persistent = false)
  164.     {
  165.         if (!DB::assertExtension('mysqli')) {
  166.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  167.         }
  168.  
  169.         $this->dsn = $dsninfo;
  170.         $conn      = false;
  171.         @ini_set('track_errors', true);
  172.  
  173.         if ($this->getOption('ssl') === true) {
  174.             $init = mysqli_init();
  175.             mysqli_ssl_set(
  176.                 $init,
  177.                 empty($dsninfo['key'])    ? null : $dsninfo['key'],
  178.                 empty($dsninfo['cert'])   ? null : $dsninfo['cert'],
  179.                 empty($dsninfo['ca'])     ? null : $dsninfo['ca'],
  180.                 empty($dsninfo['capath']) ? null : $dsninfo['capath'],
  181.                 empty($dsninfo['cipher']) ? null : $dsninfo['cipher']
  182.             );
  183.             if ($conn = @mysqli_real_connect($init,
  184.                                              $dsninfo['hostspec'],
  185.                                              $dsninfo['username'],
  186.                                              $dsninfo['password'],
  187.                                              $dsninfo['database'],
  188.                                              $dsninfo['port'],
  189.                                              $dsninfo['socket']))
  190.             {
  191.                 $conn = $init;
  192.             }
  193.         } else {
  194.             $conn = @mysqli_connect(
  195.                 $dsninfo['hostspec'],
  196.                 $dsninfo['username'],
  197.                 $dsninfo['password'],
  198.                 $dsninfo['database'],
  199.                 $dsninfo['port'],
  200.                 $dsninfo['socket']
  201.             );
  202.         }
  203.  
  204.         @ini_restore('track_errors');
  205.  
  206.         if (!$conn) {
  207.             if (($err = @mysqli_connect_error()) != '') {
  208.                 return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  209.                                          null, $err);
  210.             } elseif (empty($php_errormsg)) {
  211.                 return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  212.             } else {
  213.                 return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  214.                                          null, $php_errormsg);
  215.             }
  216.         }
  217.  
  218.         if ($dsninfo['database']) {
  219.             $this->_db = $dsninfo['database'];
  220.         }
  221.  
  222.         $this->connection = $conn;
  223.         return DB_OK;
  224.     }
  225.  
  226.     // }}}
  227.     // {{{ disconnect()
  228.  
  229.     /**
  230.      * Log out and disconnect from the database.
  231.      *
  232.      * @return boolean true on success, false if not connected
  233.      * @access public
  234.      */
  235.     function disconnect()
  236.     {
  237.         $ret = @mysqli_close($this->connection);
  238.         $this->connection = null;
  239.         return $ret;
  240.     }
  241.  
  242.     // }}}
  243.     // {{{ simpleQuery()
  244.  
  245.     /**
  246.      * Send a query to MySQL and return the results as a MySQL resource
  247.      * identifier.
  248.      *
  249.      * @param string $query the SQL query
  250.      * @return mixed a valid MySQL result for successful SELECT
  251.      *               queries, DB_OK for other successful queries.
  252.      *               A DB error is returned on failure.
  253.      * @access public
  254.      */
  255.     function simpleQuery($query)
  256.     {
  257.         $ismanip = DB::isManip($query);
  258.         $this->last_query = $query;
  259.         $query = $this->modifyQuery($query);
  260.         if ($this->_db) {
  261.             if (!@mysqli_select_db($this->connection, $this->_db)) {
  262.                 return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  263.             }
  264.         }
  265.         if (!$this->autocommit && $ismanip) {
  266.             if ($this->transaction_opcount == 0) {
  267.                 $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=0');
  268.                 $result = @mysqli_query($this->connection, 'BEGIN');
  269.                 if (!$result) {
  270.                     return $this->mysqlRaiseError();
  271.                 }
  272.             }
  273.             $this->transaction_opcount++;
  274.         }
  275.         $result = @mysqli_query($this->connection, $query);
  276.         if (!$result) {
  277.             return $this->mysqlRaiseError();
  278.         }
  279. # this next block is still sketchy..
  280.         if (is_object($result)) {
  281.             $numrows = $this->numrows($result);
  282.             if (is_object($numrows)) {
  283.                 return $numrows;
  284.             }
  285. # need to come up with different means for next line
  286. # since $result is object (int)$result won't fly...
  287. //            $this->num_rows[(int)$result] = $numrows;
  288.             return $result;
  289.         }
  290.         return DB_OK;
  291.     }
  292.  
  293.     // }}}
  294.     // {{{ nextResult()
  295.  
  296.     /**
  297.      * Move the internal mysql result pointer to the next available result.
  298.      *
  299.      * This method has not been implemented yet.
  300.      *
  301.      * @param resource $result a valid sql result resource
  302.      * @return false
  303.      * @access public
  304.      */
  305.     function nextResult($result)
  306.     {
  307.         return false;
  308.     }
  309.  
  310.     // }}}
  311.     // {{{ fetchInto()
  312.  
  313.     /**
  314.      * Fetch a row and insert the data into an existing array.
  315.      *
  316.      * Formating of the array and the data therein are configurable.
  317.      * See DB_result::fetchInto() for more information.
  318.      *
  319.      * @param resource $result    query result identifier
  320.      * @param array    $arr       (reference) array where data from the row
  321.      *                            should be placed
  322.      * @param int      $fetchmode how the resulting array should be indexed
  323.      * @param int      $rownum    the row number to fetch
  324.      *
  325.      * @return mixed DB_OK on success, null when end of result set is
  326.      *               reached or on failure
  327.      *
  328.      * @see DB_result::fetchInto()
  329.      * @access private
  330.      */
  331.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  332.     {
  333.         if ($rownum !== null) {
  334.             if (!@mysqli_data_seek($result, $rownum)) {
  335.                 return null;
  336.             }
  337.         }
  338.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  339.             $arr = @mysqli_fetch_array($result, MYSQLI_ASSOC);
  340.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  341.                 $arr = array_change_key_case($arr, CASE_LOWER);
  342.             }
  343.         } else {
  344.             $arr = @mysqli_fetch_row($result);
  345.         }
  346.         if (!$arr) {
  347.             $errno = @mysqli_errno($this->connection);
  348.             if (!$errno) {
  349.                 return null;
  350.             }
  351.             return $this->mysqlRaiseError($errno);
  352.         }
  353.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  354.             /*
  355.              * Even though this DBMS already trims output, we do this because
  356.              * a field might have intentional whitespace at the end that
  357.              * gets removed by DB_PORTABILITY_RTRIM under another driver.
  358.              */
  359.             $this->_rtrimArrayValues($arr);
  360.         }
  361.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  362.             $this->_convertNullArrayValuesToEmpty($arr);
  363.         }
  364.         return DB_OK;
  365.     }
  366.  
  367.     // }}}
  368.     // {{{ freeResult()
  369.  
  370.     /**
  371.      * Free the internal resources associated with $result.
  372.      *
  373.      * @param resource $result MySQL result identifier
  374.      * @return bool true on success, false if $result is invalid
  375.      * @access public
  376.      */
  377.     function freeResult($result)
  378.     {
  379. # need to come up with different means for next line
  380. # since $result is object (int)$result won't fly...
  381. //        unset($this->num_rows[(int)$result]);
  382.         return @mysqli_free_result($result);
  383.     }
  384.  
  385.     // }}}
  386.     // {{{ numCols()
  387.  
  388.     /**
  389.      * Get the number of columns in a result set.
  390.      *
  391.      * @param $result MySQL result identifier
  392.      *
  393.      * @access public
  394.      *
  395.      * @return int the number of columns per row in $result
  396.      */
  397.     function numCols($result)
  398.     {
  399.         $cols = @mysqli_num_fields($result);
  400.  
  401.         if (!$cols) {
  402.             return $this->mysqlRaiseError();
  403.         }
  404.  
  405.         return $cols;
  406.     }
  407.  
  408.     // }}}
  409.     // {{{ numRows()
  410.  
  411.     /**
  412.      * Get the number of rows in a result set.
  413.      *
  414.      * @param resource $result MySQL result identifier
  415.      * @return int the number of rows in $result
  416.      * @access public
  417.      */
  418.     function numRows($result)
  419.     {
  420.         $rows = @mysqli_num_rows($result);
  421.         if ($rows === null) {
  422.             return $this->mysqlRaiseError();
  423.         }
  424.         return $rows;
  425.     }
  426.  
  427.     // }}}
  428.     // {{{ autoCommit()
  429.  
  430.     /**
  431.      * Enable/disable automatic commits.
  432.      */
  433.     function autoCommit($onoff = false)
  434.     {
  435.         // XXX if $this->transaction_opcount > 0, we should probably
  436.         // issue a warning here.
  437.         $this->autocommit = $onoff ? true : false;
  438.         return DB_OK;
  439.     }
  440.  
  441.     // }}}
  442.     // {{{ commit()
  443.  
  444.     /**
  445.      * Commit the current transaction.
  446.      */
  447.     function commit()
  448.     {
  449.         if ($this->transaction_opcount > 0) {
  450.             if ($this->_db) {
  451.                 if (!@mysqli_select_db($this->connection, $this->_db)) {
  452.                     return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  453.                 }
  454.             }
  455.             $result = @mysqli_query($this->connection, 'COMMIT');
  456.             $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
  457.             $this->transaction_opcount = 0;
  458.             if (!$result) {
  459.                 return $this->mysqlRaiseError();
  460.             }
  461.         }
  462.         return DB_OK;
  463.     }
  464.  
  465.     // }}}
  466.     // {{{ rollback()
  467.  
  468.     /**
  469.      * Roll back (undo) the current transaction.
  470.      */
  471.     function rollback()
  472.     {
  473.         if ($this->transaction_opcount > 0) {
  474.             if ($this->_db) {
  475.                 if (!@mysqli_select_db($this->connection, $this->_db)) {
  476.                     return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  477.                 }
  478.             }
  479.             $result = @mysqli_query($this->connection, 'ROLLBACK');
  480.             $result = @mysqli_query($this->connection, 'SET AUTOCOMMIT=1');
  481.             $this->transaction_opcount = 0;
  482.             if (!$result) {
  483.                 return $this->mysqlRaiseError();
  484.             }
  485.         }
  486.         return DB_OK;
  487.     }
  488.  
  489.     // }}}
  490.     // {{{ affectedRows()
  491.  
  492.     /**
  493.      * Gets the number of rows affected by the data manipulation
  494.      * query.  For other queries, this function returns 0.
  495.      *
  496.      * @return integer number of rows affected by the last query
  497.      */
  498.     function affectedRows()
  499.     {
  500.         if (DB::isManip($this->last_query)) {
  501.             return @mysqli_affected_rows($this->connection);
  502.         } else {
  503.             return 0;
  504.         }
  505.      }
  506.  
  507.     // }}}
  508.     // {{{ errorNative()
  509.  
  510.     /**
  511.      * Get the native error code of the last error (if any) that
  512.      * occured on the current connection.
  513.      *
  514.      * @return int native MySQL error code
  515.      * @access public
  516.      */
  517.     function errorNative()
  518.     {
  519.         return @mysqli_errno($this->connection);
  520.     }
  521.  
  522.     // }}}
  523.     // {{{ nextId()
  524.  
  525.     /**
  526.      * Returns the next free id in a sequence
  527.      *
  528.      * @param string  $seq_name  name of the sequence
  529.      * @param boolean $ondemand  when true, the seqence is automatically
  530.      *                           created if it does not exist
  531.      *
  532.      * @return int  the next id number in the sequence.  DB_Error if problem.
  533.      *
  534.      * @internal
  535.      * @see DB_common::nextID()
  536.      * @access public
  537.      */
  538.     function nextId($seq_name, $ondemand = true)
  539.     {
  540.         $seqname = $this->getSequenceName($seq_name);
  541.         do {
  542.             $repeat = 0;
  543.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  544.             $result = $this->query("UPDATE ${seqname} ".
  545.                                    'SET id=LAST_INSERT_ID(id+1)');
  546.             $this->popErrorHandling();
  547.             if ($result === DB_OK) {
  548.                 /** COMMON CASE **/
  549.                 $id = @mysqli_insert_id($this->connection);
  550.                 if ($id != 0) {
  551.                     return $id;
  552.                 }
  553.                 /** EMPTY SEQ TABLE **/
  554.                 // Sequence table must be empty for some reason, so fill it and return 1
  555.                 // Obtain a user-level lock
  556.                 $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
  557.                 if (DB::isError($result)) {
  558.                     return $this->raiseError($result);
  559.                 }
  560.                 if ($result == 0) {
  561.                     // Failed to get the lock, bail with a DB_ERROR_NOT_LOCKED error
  562.                     return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
  563.                 }
  564.  
  565.                 // add the default value
  566.                 $result = $this->query("REPLACE INTO ${seqname} (id) VALUES (0)");
  567.                 if (DB::isError($result)) {
  568.                     return $this->raiseError($result);
  569.                 }
  570.  
  571.                 // Release the lock
  572.                 $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
  573.                 if (DB::isError($result)) {
  574.                     return $this->raiseError($result);
  575.                 }
  576.                 // We know what the result will be, so no need to try again
  577.                 return 1;
  578.  
  579.             /** ONDEMAND TABLE CREATION **/
  580.             } elseif ($ondemand && DB::isError($result) &&
  581.                 $result->getCode() == DB_ERROR_NOSUCHTABLE)
  582.             {
  583.                 $result = $this->createSequence($seq_name);
  584.                 // Since createSequence initializes the ID to be 1,
  585.                 // we do not need to retrieve the ID again (or we will get 2)
  586.                 if (DB::isError($result)) {
  587.                     return $this->raiseError($result);
  588.                 } else {
  589.                     // First ID of a newly created sequence is 1
  590.                     return 1;
  591.                 }
  592.  
  593.             /** BACKWARDS COMPAT **/
  594.             } elseif (DB::isError($result) &&
  595.                       $result->getCode() == DB_ERROR_ALREADY_EXISTS)
  596.             {
  597.                 // see _BCsequence() comment
  598.                 $result = $this->_BCsequence($seqname);
  599.                 if (DB::isError($result)) {
  600.                     return $this->raiseError($result);
  601.                 }
  602.                 $repeat = 1;
  603.             }
  604.         } while ($repeat);
  605.  
  606.         return $this->raiseError($result);
  607.     }
  608.  
  609.     /**
  610.      * Creates a new sequence
  611.      *
  612.      * @param string $seq_name  name of the new sequence
  613.      *
  614.      * @return int  DB_OK on success.  A DB_Error object is returned if
  615.      *              problems arise.
  616.      *
  617.      * @internal
  618.      * @see DB_common::createSequence()
  619.      * @access public
  620.      */
  621.     function createSequence($seq_name)
  622.     {
  623.         $seqname = $this->getSequenceName($seq_name);
  624.         $res = $this->query("CREATE TABLE ${seqname} ".
  625.                             '(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'.
  626.                             ' PRIMARY KEY(id))');
  627.         if (DB::isError($res)) {
  628.             return $res;
  629.         }
  630.         // insert yields value 1, nextId call will generate ID 2
  631.         return $this->query("INSERT INTO ${seqname} (id) VALUES (0)");
  632.     }
  633.  
  634.     // }}}
  635.     // {{{ dropSequence()
  636.  
  637.     /**
  638.      * Deletes a sequence
  639.      *
  640.      * @param string $seq_name  name of the sequence to be deleted
  641.      *
  642.      * @return int  DB_OK on success.  DB_Error if problems.
  643.      *
  644.      * @internal
  645.      * @see DB_common::dropSequence()
  646.      * @access public
  647.      */
  648.     function dropSequence($seq_name)
  649.     {
  650.         return $this->query('DROP TABLE ' . $this->getSequenceName($seq_name));
  651.     }
  652.  
  653.     // }}}
  654.     // {{{ _BCsequence()
  655.  
  656.     /**
  657.      * Backwards compatibility with old sequence emulation implementation
  658.      * (clean up the dupes).
  659.      *
  660.      * @param string $seqname The sequence name to clean up
  661.      * @return mixed DB_Error or true
  662.      */
  663.     function _BCsequence($seqname)
  664.     {
  665.         // Obtain a user-level lock... this will release any previous
  666.         // application locks, but unlike LOCK TABLES, it does not abort
  667.         // the current transaction and is much less frequently used.
  668.         $result = $this->getOne("SELECT GET_LOCK('${seqname}_lock',10)");
  669.         if (DB::isError($result)) {
  670.             return $result;
  671.         }
  672.         if ($result == 0) {
  673.             // Failed to get the lock, can't do the conversion, bail
  674.             // with a DB_ERROR_NOT_LOCKED error
  675.             return $this->mysqlRaiseError(DB_ERROR_NOT_LOCKED);
  676.         }
  677.  
  678.         $highest_id = $this->getOne("SELECT MAX(id) FROM ${seqname}");
  679.         if (DB::isError($highest_id)) {
  680.             return $highest_id;
  681.         }
  682.         // This should kill all rows except the highest
  683.         // We should probably do something if $highest_id isn't
  684.         // numeric, but I'm at a loss as how to handle that...
  685.         $result = $this->query("DELETE FROM ${seqname} WHERE id <> $highest_id");
  686.         if (DB::isError($result)) {
  687.             return $result;
  688.         }
  689.  
  690.         // If another thread has been waiting for this lock,
  691.         // it will go thru the above procedure, but will have no
  692.         // real effect
  693.         $result = $this->getOne("SELECT RELEASE_LOCK('${seqname}_lock')");
  694.         if (DB::isError($result)) {
  695.             return $result;
  696.         }
  697.         return true;
  698.     }
  699.  
  700.     // }}}
  701.     // {{{ quoteIdentifier()
  702.  
  703.     /**
  704.      * Quote a string so it can be safely used as a table or column name
  705.      *
  706.      * Quoting style depends on which database driver is being used.
  707.      *
  708.      * MySQL can't handle the backtick character (<kbd>`</kbd>) in
  709.      * table or column names.
  710.      *
  711.      * @param string $str  identifier name to be quoted
  712.      *
  713.      * @return string  quoted identifier string
  714.      *
  715.      * @since 1.6.0
  716.      * @access public
  717.      * @internal
  718.      */
  719.     function quoteIdentifier($str)
  720.     {
  721.         return '`' . $str . '`';
  722.     }
  723.  
  724.     // }}}
  725.     // {{{ escapeSimple()
  726.  
  727.     /**
  728.      * Escape a string according to the current DBMS's standards
  729.      *
  730.      * @param string $str  the string to be escaped
  731.      *
  732.      * @return string  the escaped string
  733.      *
  734.      * @internal
  735.      */
  736.     function escapeSimple($str) {
  737.         return @mysqli_real_escape_string($this->connection, $str);
  738.     }
  739.  
  740.     // }}}
  741.     // {{{ modifyQuery()
  742.  
  743.     function modifyQuery($query)
  744.     {
  745.         return $query;
  746.     }
  747.  
  748.     // }}}
  749.     // {{{ modifyLimitQuery()
  750.  
  751.     function modifyLimitQuery($query, $from, $count, $params = array())
  752.     {
  753.         if (DB::isManip($query)) {
  754.             return $query . " LIMIT $count";
  755.         } else {
  756.             return $query . " LIMIT $from, $count";
  757.         }
  758.     }
  759.  
  760.     // }}}
  761.     // {{{ mysqlRaiseError()
  762.  
  763.     /**
  764.      * Gather information about an error, then use that info to create a
  765.      * DB error object and finally return that object.
  766.      *
  767.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  768.      *                          manually raising an error
  769.      * @return object  DB error object
  770.      * @see DB_common::errorCode()
  771.      * @see DB_common::raiseError()
  772.      */
  773.     function mysqlRaiseError($errno = null)
  774.     {
  775.         if ($errno === null) {
  776.             if ($this->options['portability'] & DB_PORTABILITY_ERRORS) {
  777.                 $this->errorcode_map[1022] = DB_ERROR_CONSTRAINT;
  778.                 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT_NOT_NULL;
  779.                 $this->errorcode_map[1062] = DB_ERROR_CONSTRAINT;
  780.             } else {
  781.                 // Doing this in case mode changes during runtime.
  782.                 $this->errorcode_map[1022] = DB_ERROR_ALREADY_EXISTS;
  783.                 $this->errorcode_map[1048] = DB_ERROR_CONSTRAINT;
  784.                 $this->errorcode_map[1062] = DB_ERROR_ALREADY_EXISTS;
  785.             }
  786.             $errno = $this->errorCode(mysqli_errno($this->connection));
  787.         }
  788.         return $this->raiseError($errno, null, null, null,
  789.                                  @mysqli_errno($this->connection) . ' ** ' .
  790.                                  @mysqli_error($this->connection));
  791.     }
  792.  
  793.     // }}}
  794.     // {{{ tableInfo()
  795.  
  796.     /**
  797.      * Returns information about a table or a result set.
  798.      *
  799.      * WARNING: this method will probably not work because the mysqli_*()
  800.      * functions it relies upon may not exist.
  801.      *
  802.      * @param object|string  $result  DB_result object from a query or a
  803.      *                                string containing the name of a table
  804.      * @param int            $mode    a valid tableInfo mode
  805.      * @return array  an associative array with the information requested
  806.      *                or an error object if something is wrong
  807.      * @access public
  808.      * @internal
  809.      * @see DB_common::tableInfo()
  810.      */
  811.     function tableInfo($result, $mode = null) {
  812.         if (isset($result->result)) {
  813.             /*
  814.              * Probably received a result object.
  815.              * Extract the result resource identifier.
  816.              */
  817.             $id = $result->result;
  818.             $got_string = false;
  819.         } elseif (is_string($result)) {
  820.             /*
  821.              * Probably received a table name.
  822.              * Create a result resource identifier.
  823.              */
  824.             $id = @mysqli_query($this->connection,
  825.                                 "SELECT * FROM $result LIMIT 0");
  826.             $got_string = true;
  827.         } else {
  828.             /*
  829.              * Probably received a result resource identifier.
  830.              * Copy it.
  831.              * Deprecated.  Here for compatibility only.
  832.              */
  833.             $id = $result;
  834.             $got_string = false;
  835.         }
  836.  
  837.         if (!is_a($id, 'mysqli_result')) {
  838.             return $this->mysqlRaiseError(DB_ERROR_NEED_MORE_DATA);
  839.         }
  840.  
  841.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  842.             $case_func = 'strtolower';
  843.         } else {
  844.             $case_func = 'strval';
  845.         }
  846.  
  847.         $count = @mysqli_num_fields($id);
  848.  
  849.         // made this IF due to performance (one if is faster than $count if's)
  850.         if (!$mode) {
  851.             for ($i=0; $i<$count; $i++) {
  852.                 $tmp = @mysqli_fetch_field($id);
  853.                 $res[$i]['table'] = $case_func($tmp->table);
  854.                 $res[$i]['name']  = $case_func($tmp->name);
  855.                 $res[$i]['type']  = isset($this->mysqli_types[$tmp->type]) ?
  856.                                           $this->mysqli_types[$tmp->type] :
  857.                                           'unknown';
  858.                 $res[$i]['len']   = $tmp->max_length;
  859.  
  860.                 $res[$i]['flags'] = '';
  861.                 foreach ($this->mysqli_flags as $const => $means) {
  862.                     if ($tmp->flags & $const) {
  863.                         $res[$i]['flags'] .= $means . ' ';
  864.                     }
  865.                 }
  866.                 if ($tmp->def) {
  867.                     $res[$i]['flags'] .= 'default_' . rawurlencode($tmp->def);
  868.                 }
  869.                 $res[$i]['flags'] = trim($res[$i]['flags']);
  870.             }
  871.         } else { // full
  872.             $res['num_fields']= $count;
  873.  
  874.             for ($i=0; $i<$count; $i++) {
  875.                 $tmp = @mysqli_fetch_field($id);
  876.                 $res[$i]['table'] = $case_func($tmp->table);
  877.                 $res[$i]['name']  = $case_func($tmp->name);
  878.                 $res[$i]['type']  = isset($this->mysqli_types[$tmp->type]) ?
  879.                                           $this->mysqli_types[$tmp->type] :
  880.                                           'unknown';
  881.                 $res[$i]['len']   = $tmp->max_length;
  882.  
  883.                 $res[$i]['flags'] = '';
  884.                 foreach ($this->mysqli_flags as $const => $means) {
  885.                     if ($tmp->flags & $const) {
  886.                         $res[$i]['flags'] .= $means . ' ';
  887.                     }
  888.                 }
  889.                 if ($tmp->def) {
  890.                     $res[$i]['flags'] .= 'default_' . rawurlencode($tmp->def);
  891.                 }
  892.                 $res[$i]['flags'] = trim($res[$i]['flags']);
  893.  
  894.                 if ($mode & DB_TABLEINFO_ORDER) {
  895.                     $res['order'][$res[$i]['name']] = $i;
  896.                 }
  897.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  898.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  899.                 }
  900.             }
  901.         }
  902.  
  903.         // free the result only if we were called on a table
  904.         if ($got_string) {
  905.             @mysqli_free_result($id);
  906.         }
  907.         return $res;
  908.     }
  909.  
  910.     // }}}
  911.     // {{{ getSpecialQuery()
  912.  
  913.     /**
  914.      * Returns the query needed to get some backend info.
  915.      *
  916.      * @param string $type What kind of info you want to retrieve
  917.      * @return string The SQL query string
  918.      */
  919.     function getSpecialQuery($type)
  920.     {
  921.         switch ($type) {
  922.             case 'tables':
  923.                 return 'SHOW TABLES';
  924.             case 'views':
  925.                 return DB_ERROR_NOT_CAPABLE;
  926.             case 'users':
  927.                 $sql = 'select distinct User from user';
  928.                 if ($this->dsn['database'] != 'mysql') {
  929.                     $dsn = $this->dsn;
  930.                     $dsn['database'] = 'mysql';
  931.                     if (DB::isError($db = DB::connect($dsn))) {
  932.                         return $db;
  933.                     }
  934.                     $sql = $db->getCol($sql);
  935.                     $db->disconnect();
  936.                     // XXX Fixme the mysql driver should take care of this
  937.                     if (!@mysqli_select_db($this->connection, $this->dsn['database'])) {
  938.                         return $this->mysqlRaiseError(DB_ERROR_NODBSELECTED);
  939.                     }
  940.                 }
  941.                 return $sql;
  942.             case 'databases':
  943.                 return 'SHOW DATABASES';
  944.             default:
  945.                 return null;
  946.         }
  947.     }
  948.  
  949.    // }}}
  950.  
  951. }
  952.  
  953. /*
  954.  * Local variables:
  955.  * tab-width: 4
  956.  * c-basic-offset: 4
  957.  * End:
  958.  */
  959.  
  960. ?>
  961.